package com.yanqu.road.server.manger.activity.share;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yanqu.road.dao.db.DbNameStrategy;
import com.yanqu.road.dao.db.DBManager;
import com.yanqu.road.dao.impl.activity.share.InvitedDataDaoImpl;
import com.yanqu.road.dao.impl.activity.share.OpenInvitedDataDaoImpl;
import com.yanqu.road.dao.impl.activity.share.ShareDataDaoImpl;
import com.yanqu.road.dao.impl.log.LogUserInfoDaoImpl;
import com.yanqu.road.entity.activity.share.config.ShareConfig;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.log.LogUserInfo;
import com.yanqu.road.entity.player.OpenInvitedData;
import com.yanqu.road.entity.player.ShareInvitationData;
import com.yanqu.road.logic.redis.RedisManger;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.share.ShareModule;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ShareMgr extends TempMgr {

    private static Map<Long, List<ShareInvitationData>> shareDataMap = new ConcurrentHashMap<>(64);
    private static Map<Long, String> shareCodeMap = new ConcurrentHashMap<>();
    private static Map<Long, Integer> invitationNumMap = new ConcurrentHashMap<>();
    private static RandomHelper randomHelper = new RandomHelper();

    // openId、邀请改openId的邀请码
    private static Map<String, OpenInvitedData> openInvitedDataMap = new ConcurrentHashMap<>();

    public static void changeShareData(long userId, long invitationServerId, long invitationUserId, BigInteger earnSpeed, long rechargeValue, long registerTime, String openId) {
        if (StringUtils.isNullOrEmpty(openId)) {
            return;
        }
        ShareConfig config = ShareActivityMgr.getConfig();
        if (config == null) {
            return;
        }
        synchronized (shareDataMap) {
            List<ShareInvitationData> dataList = shareDataMap.get(userId);
            if (dataList == null) {
                dataList = new ArrayList<>();
                shareDataMap.put(userId, dataList);
            }
            ShareInvitationData data = null;
            for (ShareInvitationData invitationData : dataList) {
                if (Objects.equals(openId, invitationData.getOpenId())) {
                    data = invitationData;
                    break;
                }
            }
            GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);

            if (data == null) {
                int num = getNum(registerTime, dataList);
                if (num >= ShareActivityMgr.getConfig().getShareDayMaxPerson()) {
                    return;
                }
                data = new ShareInvitationData();
                data.setUserId(userId);
                data.setInvitationServerId(invitationServerId);
                data.setInvitationUserId(invitationUserId);
                data.setRegisterTime(registerTime);
                data.setVip(rechargeValue);
                data.setEarnSpeed(earnSpeed);
                data.setOpenId(openId);
                data.setInsertOption();
                dataList.add(data);
                if (player != null) {
                    player.getModule(ShareModule.class).syncShareDataMsg();
                }
            }

            // 赚速取历史最高，被邀请玩家信息同时更新
            if (earnSpeed.compareTo(data.getEarnSpeed()) > 0) {
                data.setEarnSpeed(earnSpeed);
                data.setInvitationServerId(invitationServerId);
                data.setInvitationUserId(invitationUserId);
            }
            // VIP取最高
            if (rechargeValue > data.getVip()) {
                data.setVip(rechargeValue);
            }

            if (player != null) {
                player.notifyListener(eGamePlayerEventType.ShareNum.getValue());
                player.notifyListener(eGamePlayerEventType.ShareEarnSpeed.getValue());
                player.notifyListener(eGamePlayerEventType.ShareRecharge.getValue());
            }
        }

    }

    public static int getNum(long time,List<ShareInvitationData> dataList) {
        int todayNum = 0;
        if (dataList != null) {
            for (ShareInvitationData invitationData : new ArrayList<>(dataList)) {
                if (invitationData == null) {
                    continue;
                }
                long registerTime = invitationData.getRegisterTime();
                if (DateHelper.isSameDay(time, registerTime)) {
                    todayNum++;
                }
            }
        }
        return todayNum;
    }

    public static List<ShareInvitationData> getShareInvitationDataList(long userId) {
        List<ShareInvitationData> dataList = shareDataMap.get(userId);
        if (dataList == null) {
            return new ArrayList<>();
        }
        return new ArrayList<>(dataList);
    }

    public static String getShareCode(long userId) {
        String code = shareCodeMap.get(userId);
        if (code == null) {
            long serverId = GameServer.getInstance().getServerId();
            code = serverId + "_" + userId + "_" + randomHelper.randomString(6);
            shareCodeMap.put(userId, code);
        }
        return code;
    }

    public static int getInviteNum(long userId,long time) {
        List<ShareInvitationData> dataList = shareDataMap.get(userId);
        if (dataList == null) {
            return 0;
        }
        if (userId == 301001520001603L) {
            getLogger().info("user: {}, invitationData:  {}",userId, JSON.toJSONString(dataList));
        }
        return getNum(time,dataList);
    }


    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        shareCodeMap = new ShareDataDaoImpl().getAllCode();
        reloadShareDataMap(); // shareDataMap
        reloadOpenInvitedDataMap(); // openInvitedDataMap
        return true;
    }

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean stop() {
        return true;
    }

    @Override
    public boolean save() {
        if (shareDataMap != null) {
            for (List<ShareInvitationData> list : new ArrayList<>(shareDataMap.values())) {
                for (ShareInvitationData data : new ArrayList<>(list)) {
                    if (data == null) {
                        continue;
                    }
                    if (StringUtils.isNullOrEmpty(data.getOpenId())) {
                        continue;
                    }
                    if (data.isInsertOption()) {
                        new InvitedDataDaoImpl().add(data);
                    } else if (data.isUpdateOption()) {
                        new InvitedDataDaoImpl().update(data);
                    }
                }
            }
            synchronized (shareDataMap) {
                for (List<ShareInvitationData> dataList : new ArrayList<>(shareDataMap.values())) {
                    dataList.removeIf(Objects::isNull);
                }
            }
        }
        return true;
    }

    /**
     * 刷新邀请码库
     */
    public static void reloadOpenInvitedDataMap() {
//        openInvitedDataMap = new OpenInvitedDataDaoImpl().getOpenInvitedDataMap();
    }

    /**
     * 获取邀请数据
     */
    private static void reloadShareDataMap() {
        Map<Long, List<ShareInvitationData>> tmpData = new InvitedDataDaoImpl().getShareInvitationData();

        // 旧数据没有openId，需要去中心库查
        Set<Long> noOpenIdSet = new HashSet<>();
        Map<Long, List<ShareInvitationData>> tmpMap = new ConcurrentHashMap<>(); // 放引用，便于设置openId，正常list只会有1条数据
        for (List<ShareInvitationData> list : tmpData.values()) {
            for (ShareInvitationData data : list) {
                // 没有openId的才需要查
                if (StringUtils.isNullOrEmpty(data.getOpenId())) {
                    long userId = getUserIdByAliasId(data.getInvitationServerId(), data.getInvitationUserId());
                    noOpenIdSet.add(userId);
                    if (!tmpMap.containsKey(userId)) {
                        tmpMap.put(userId, new ArrayList<>());
                    }
                    tmpMap.get(userId).add(data);
                }
            }
        }
        List<Long> userIdList = new ArrayList<>(noOpenIdSet);
        // 避免sql超长，一次最多查500
        for (int times = 0; times < 999; times++) {
            // 确定查询范围
            int startIndex = times * 500;
            int endIndex = (times + 1) * 500 - 1;
            if (endIndex >= userIdList.size()) endIndex = userIdList.size() - 1;
            if (startIndex > endIndex) {
                // 结束
                break;
            }
            List<Long> tmpIdList = new ArrayList<>();
            for (int index = startIndex; index <= endIndex; index++) {
                tmpIdList.add(userIdList.get(index));
            }
            // 查询、设置openId
            List<LogUserInfo> logUserInfoList = new LogUserInfoDaoImpl().getUserServerListByOpenId(tmpIdList);
            for (LogUserInfo logUserInfo : logUserInfoList) {
                List<ShareInvitationData> dataList = tmpMap.get(logUserInfo.getUserId());
                if (dataList != null) {
                    for (ShareInvitationData data : dataList) {
                        data.setOpenId(logUserInfo.getOpenId());
                        // 游戏服添加openId的方法不是updateData
                        new InvitedDataDaoImpl().updateDataByOldKey(data);
                        // 进到这里说明这条data是旧数据，尝试中心库添加一下该openId的邀请码
                        OpenInvitedData openInvitedData = new OpenInvitedData();
                        openInvitedData.setOpenId(logUserInfo.getOpenId()); // 被邀请人openId
                        openInvitedData.setInvitedCode(getShareCode(data.getUserId())); // 邀请人邀请码
                        openInvitedData.setRegisterTime(data.getRegisterTime()); // 邀请人注册时间
                        new OpenInvitedDataDaoImpl().add(openInvitedData);
                        try {
                            JSONObject object = new JSONObject();
                            object.put("openId",openInvitedData.getOpenId());
                            object.put("invitedCode",openInvitedData.getInvitedCode());
                            object.put("registerTime",openInvitedData.getRegisterTime());
                            RedisManger.getRedisUtil().setString("PLAYER-INVITED-" + openInvitedData.getOpenId(),JSON.toJSONString(object));
                        } catch (Exception e) {
                            getLogger().error("add invited code error",e);
                        }
                      //  new OpenInvitedDataDaoImpl().update(openInvitedData);
                    }
                }
            }
        }

        shareDataMap = tmpData;
    }

    /**
     * 获取openId邀请信息
     *
     * @return null 没有邀请码
     */
    public static OpenInvitedData getOpenInvitedData(String openId) {
        OpenInvitedData invitedData = openInvitedDataMap.get(openId);
        if (invitedData != null) {
            return invitedData;
        }
        Long hashCode = (long) openId.hashCode();
        Integer lastTime = invitationNumMap.getOrDefault(hashCode,0);
        if (lastTime == null) {
            lastTime = 0;
        }
        int curTime = (int) (System.currentTimeMillis() / 1000);
        if (curTime - lastTime < 30 * 60) {
            //小于 三分钟 不重新查了
            return null;
        }
        invitationNumMap.put(hashCode, curTime);
 /*       DBManager db = new OpenInvitedDataDaoImpl().getDb();
        ResultSet rs = null;
        CallableStatement call = null;
        try {
            db.setConnName(DbNameStrategy.getServerDb());
            String sql = "select * from t_s_open_invited_data where openId = ?";
            call = db.getConnection().prepareCall(sql);
            call.setString(1, openId);
            rs = call.executeQuery();
            if (rs.next()) {
                OpenInvitedData openInvitedData = new OpenInvitedData();
                openInvitedData.setOpenId(rs.getString("openId"));
                openInvitedData.setInvitedCode(rs.getString("invitedCode"));
                openInvitedData.setRegisterTime(rs.getLong("registerTime"));
                openInvitedDataMap.put(openId, openInvitedData);
            }
        } catch (Exception e) {
           getLogger().error("get invited data error. openId: {}",openId, e);
        } finally {
           db.closeConnection(call, rs);
        }*/
        try {
            String s = RedisManger.getRedisUtil().get("PLAYER-INVITED-" + openId);
            if (s != null) {
                JSONObject object = JSON.parseObject(s);
                OpenInvitedData openInvitedData = new OpenInvitedData();
                openInvitedData.setOpenId(object.getString("openId"));
                openInvitedData.setInvitedCode(object.getString("invitedCode"));
                openInvitedData.setRegisterTime(object.getLong("registerTime"));
                openInvitedDataMap.put(openId, openInvitedData);
            }
        } catch (Exception e) {
            getLogger().error("get invited data error. openId: {}", openId, e);
        }
        return openInvitedDataMap.get(openId);
    }

    /**
    * 描述：把短用户编号转换回长用户编号
    * 作者：zrq
    * 时间：2022/8/10
    * 参数：
    服务器编号，短用户编号
    * 返回值：长用户编号
    **/
    private static long getUserIdByAliasId(long serverId, long aliasId) {
        // userId：8位区服ID + 7位自增
        // aliasId：1 + userId去掉前5位（剩3位区服ID + 7位自增）
        String aliasIdStr = String.valueOf(aliasId);
        String userId = serverId + "" + aliasIdStr.substring(aliasIdStr.length() - 7);
        return Long.valueOf(userId);
    }
}
